﻿using System;
using System.Data;
using System.Data.SqlClient;
using System.Diagnostics;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
using MSPE.Public.FOSS.AutoStatusPlus.Common;

namespace MSPE.Public.FOSS.AutoStatusPlus.TimerJob
{
    public class StatusingTimerJob : SPJobDefinition
    {
        #region Public Properties
        public string Url { get; set; }
        #endregion // Public Properties

        #region Private / Protected
        private EventEntry _eventLog;
        private const string _baseJobTitle = "AutoStatusPlus Statusing Job";
        private const string _eventSourceName = "AutoStatusPlus StatusingTimerJob";
        #endregion // Private / Protected

        #region Constructors
        /// <summary>
        /// Constructs a new instance of the <see cref="StatusingTimerJob" /> class.
        /// </summary>
        public StatusingTimerJob() : base()
        {
            Url = String.Empty;
        } // StatusingTimerJob()

        public StatusingTimerJob(string jobName, SPWebApplication webApplication, SPJobLockType lockType, string pwaUrl)
            : base(jobName, webApplication, null, lockType)
        {
            Url = String.Empty;

            if (!Properties.ContainsKey(GlobalConstants.UrlKey))
                Properties.Add(GlobalConstants.UrlKey, pwaUrl);

            Properties[GlobalConstants.UrlKey] = pwaUrl;

            Title = _baseJobTitle + " - " + pwaUrl;
        } // StatusingTimerJob()
        #endregion // Constructors

        #region Methods
        private DataSet RetrieveTimesheets(SqlConnection cn)
        {
            DataSet _ds;
            SqlDataAdapter _da = null;
            SqlCommand _cmdRetrieve = null;

            try
            {
                _ds = new DataSet();
                _cmdRetrieve = new SqlCommand(GlobalConstants.SqlGetUnprocessedTimesheetsProcName, cn)
                                   {CommandType = CommandType.StoredProcedure};
                _da = new SqlDataAdapter(_cmdRetrieve);
                _da.Fill(_ds);
                return _ds;     
            } // End try

            catch (Exception ex)
            {
                _eventLog.WriteEvent(ex.Message);
                throw;
            } // End catch

            finally
            {
                if (_da != null) _da.Dispose();
                if (_cmdRetrieve != null) _cmdRetrieve.Dispose();
            } // End finally
        } // RetrieveTimesheets()

        private void UpdateStatus(SqlConnection cn, int id, bool result)
        {
            SqlCommand _cmdUpdate = null;

            try
            {                
                _cmdUpdate = result ? new SqlCommand(GlobalConstants.SqlMarkTimesheetAsProcessedProcName, cn) : new SqlCommand(GlobalConstants.SqlMarkTimesheetAsFailedProcName, cn);

                _cmdUpdate.CommandType = CommandType.StoredProcedure;
                SqlParameter _parm = new SqlParameter("id", SqlDbType.Int, 4) {Value = id};
                _cmdUpdate.Parameters.Add(_parm);
                _cmdUpdate.ExecuteNonQuery();
            } // End try

            catch (Exception ex)
            {
                _eventLog.WriteEvent(ex.Message);
                throw;
            } // End catch

            finally
            {
                if (_cmdUpdate != null) _cmdUpdate.Dispose();
            } // End finally
        } // UpdateStatus()

        #region Overrides
        public override void Execute(Guid targetInstanceId)
        {
            SPSite _pwaSite = null;
            SPWeb _pwaWeb = null;

            try
            {
                _pwaSite = new SPSite(Properties[GlobalConstants.UrlKey].ToString());
                _pwaWeb = _pwaSite.RootWeb;
                _eventLog = new EventEntry(_eventSourceName);

                Settings _loadedSettings = Settings.LoadSettings(_pwaWeb);

                UpdateStatus _status = _loadedSettings.SspHostname != GlobalConstants.SspHostnameInitialValue ? new UpdateStatus(_loadedSettings.SspHostname) : new UpdateStatus(String.Empty);

                if (_pwaWeb == null)
                    throw new Exception("Could not access the feature's parent Site.");

                if (_pwaWeb.WebTemplateId != GlobalConstants.PwaSiteTemplateId)
                    throw new Exception("This feature may only be activated on Project Web Access Sites.");

                if (!Utility.AllKeysExist(_pwaWeb))
                    return;

                // TODO: Add processing window functionality
                //if (!ReadyToProcess()) return;

                string _connString = Utility.BuildConnectionString(_loadedSettings.DbUseIntegratedAuth,
                    _loadedSettings.DbServer, _loadedSettings.DbName, _loadedSettings.DbUser, _loadedSettings.DbPassword);

                using (SqlConnection _cn = new SqlConnection(_connString))
                {
                    _cn.Open();
                    DataSet _ds = RetrieveTimesheets(_cn);

                    foreach (DataRow _row in _ds.Tables[0].Rows)
                    {
                        if (_loadedSettings.LogTimesheetEvents) 
                            _eventLog.WriteEvent("siteGuid=" + _row["siteGuid"].ToString() + ", tsGuid=" + _row["tsGuid"].ToString(), EventLogEntryType.Information);
                        
                        bool _result = _status.ProcessTimesheet((Guid)_row["siteGuid"], (Guid)_row["tsGuid"],
                                                              _row["lcid"].ToString(), _row["userName"].ToString(), 
                                                              true, _loadedSettings.SspName);

                        if (_loadedSettings.LogTimesheetEvents) 
                            _eventLog.WriteEvent("Update status on row " + _row["ID"].ToString(), EventLogEntryType.Information);
                        
                        UpdateStatus(_cn, (int)_row["ID"], _result);
                    } // End foreach
                } // End using
            } // End try

            catch (Exception ex)
            {
                _eventLog.WriteEvent(ex.Message);
            } // End catch

            finally
            {
                if (_pwaSite != null) _pwaSite.Dispose();
                if (_pwaWeb != null) _pwaWeb.Dispose();
                if (_eventLog != null) _eventLog.Dispose();
            } // End finally
        } // Execute()
        #endregion // Overrides
        #endregion // Methods
    }
}
